package gpl.scotlandyard.fugitive.hint.home;

import gpl.androidcommons.service.MapLoaderPerformer;
import gpl.androidcommons.service.ScheduleServiceListener;
import gpl.scotlandyard.beans.basics.Node;
import gpl.scotlandyard.beans.basics.Player;
import gpl.scotlandyard.exceptions.InvalidUserInputException;
import gpl.scotlandyard.fugitive.hint.ApplicationManager;
import gpl.scotlandyard.fugitive.hint.R;
import gpl.scotlandyard.fugitive.hint.result.ResultActivity;
import gpl.scotlandyard.services.PathFinder;
import gpl.scotlandyard.services.basics.BoardManagerBuilder;
import gpl.scotlandyard.utils.Scotlandyard;

import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class HomeActivity extends Activity implements ScheduleServiceListener<List<Node>> {

  private static final String TAG = HomeActivity.class.toString();

  private PlayersListAdapter listAdapter;
  private List<Node> boardMap;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.home_activity);
    final ListView listview = (ListView) findViewById(R.id.home_players_list);
    listAdapter = new PlayersListAdapter(this, R.layout.home_players_view, getPlayersList());
    listview.setAdapter(listAdapter);
    ApplicationManager.loadConfig(this);
    loadMap();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.home, menu);
    return true;
  }

  private List<Player> getPlayersList() {
    LinkedList<Player> players = new LinkedList<Player>();
    Player fugitive = new Player(getString(R.string.fugitive_name), true);
    fugitive.setNode(null);
    players.add(fugitive);
    for (int i = 1; i <= Scotlandyard.Consts.NB_MAX_DETECTIVES; i++) {
      Player detective = new Player(getString(R.string.detective_default_name) + " " + i);
      detective.setNode(null);
      players.add(detective);
    }
    return players;
  }

  public void clickFindAWay(View view) {
    List<Player> availablePlayers = listAdapter.getAvailablePlayers();
    PathFinder pathFinder = null;
    try {
      pathFinder = generatePathFinder(availablePlayers);
    } catch (InvalidUserInputException e) {
      Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
      return;
    }
    ApplicationManager.push(ResultActivity.ARG_PATH_FINDER, pathFinder);
    startActivity(new Intent(this, ResultActivity.class));
  }

  private PathFinder generatePathFinder(List<Player> availablePlayers) throws InvalidUserInputException {
    BoardManagerBuilder builder = new BoardManagerBuilder();
    builder.setMap(boardMap);
    int fugitivePosition = -1;
    List<Integer> detectivePositions = new LinkedList<Integer>();
    boolean hasFugitive = false;
    if (availablePlayers.size() < 2) {
      String msg = getString(R.string.home_need_positions);
      throw new InvalidUserInputException(msg);
    }
    for (Player player : availablePlayers) {
      if (player.isFugitive()) {
        builder.addFugitive(player);
        fugitivePosition = player.getNode().getNumber();
        hasFugitive = true;
      } else {
        builder.addDetective(player);
        if (detectivePositions.contains(player.getNode().getNumber())) {
          String msg = getString(R.string.home_invalid_position, player.getName(), player.getNode().getNumber());
          throw new InvalidUserInputException(msg);
        }
        if (fugitivePosition == player.getNode().getNumber()) {
          String msg = getString(R.string.home_already_catch, player.getName());
          throw new InvalidUserInputException(msg);
        }
        detectivePositions.add(player.getNode().getNumber());
      }
    }
    if (!hasFugitive) {
      String msg = getString(R.string.home_missg_fugitive_position);
      throw new InvalidUserInputException(msg);
    }
    builder.initializePlayersTickets();
    PathFinder pathFinder = new PathFinder(builder.getBoardManager().getBoard());

    try {
      pathFinder.setPlayersPositions(fugitivePosition, detectivePositions);
    } catch (InvalidUserInputException e) {
      throw new InvalidUserInputException(e.getMessage());
    }
    return pathFinder;
  }

  private void enableLaunchButton() {
    Button launchButton = (Button) findViewById(R.id.home_find_button);
    launchButton.setText(R.string.home_find_button);
    launchButton.setEnabled(true);
  }

  /** Uses loader service to build the map. */
  private void loadMap() {
    Log.i(TAG, "no map loaded");
    MapLoaderPerformer mapService = new MapLoaderPerformer(getAssets(), Scotlandyard.Config.MAP_FILE, this);
    ApplicationManager.schedule(mapService, 250);
    Log.i(TAG, "launch job");
  }

  @Override
  public void done(final List<Node> result) {
    final HomeActivity activity = this;
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Log.i(TAG, "job finished");
        activity.boardMap = result;
        enableLaunchButton();
      }
    });
  }

  @Override
  public void failed(final Exception e) {
    final Activity activity = this;
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Log.e(TAG, "impossible to load map : " + e.getLocalizedMessage());
        new AlertDialog.Builder(activity).setMessage(R.string.error_load_map).create().show();
        Log.e(TAG, "stop application");
        finish();
      }
    });
  }
}
